package com.jianjun.common.util;


import org.apache.log4j.Layout;
import org.apache.log4j.Priority;
import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.spi.LoggingEvent;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Date;
import java.util.Locale;

/**
 * 修改log的生成策略(一天一个目录,每次重启日志文件切换新的)
 *
 * @author source
 */
public class MyRollingFileAppender extends RollingFileAppender {
    private LocalDate localDate = null;
    private String parentFileName = null;

    /**
     * 默认的无参构造
     */
    public MyRollingFileAppender() {
        super();
    }

    /**
     * 三参构造
     */
    public MyRollingFileAppender(Layout layout, String filename, boolean append) throws IOException {
        super(layout, filename, append);
        parentFileName = filename;
    }

    /**
     * 二参构造(append->true)
     */
    public MyRollingFileAppender(Layout layout, String filename) throws IOException {
        super(layout, filename);
    }

    /**
     * 修改fileName方法在截断生成新文件前调用
     */
    @Override
    public void setFile(String file) {
        if (parentFileName == null) {
            parentFileName = file;
        }
        super.fileName = DatePatternParser.parse(new StringBuilder(parentFileName));
    }

    /**
     * 当前日志输出行只输出到对应的日志等级文件(不做向下兼容)
     */
    @Override
    public boolean isAsSevereAsThreshold(Priority priority) {
        return this.getThreshold().equals(priority);
    }


    /**
     * 修改日志策略主要逻辑
     */
    @Override
    protected void subAppend(LoggingEvent event) {
        boolean rollOver = false;
        //重启且有日志生成新文件
        if (localDate == null) {
            localDate = LocalDate.now();
            if (new File(fileName).length() > 0) {
                rollOver = true;
            }
        }
        if (fileName != null && qw != null) {
            long size = ((CountingQuietWriter) qw).getCount();
            long nextRollover = 0;
            //添加日期判断,确保变更日期触发日志截断
            boolean flag = (size >= maxFileSize && size >= nextRollover) || !LocalDate.now().equals(localDate);
            if (flag) {
                localDate = LocalDate.now();
                rollOver = true;
            }
        }
        //如果存在换文件操作,就在换完文件后再输出日志
        if (rollOver) {
            setFile(parentFileName);
            rollOver();
        }
        super.subAppend(event);
    }


    /**
     * 路径带时间字符串格式化
     */
    static class DatePatternParser {
        static final String HEAD = "%d";

        static String parse(StringBuilder str) {
            while (str.indexOf(HEAD) > 0) {
                int index = str.indexOf(HEAD);
                int indexEnd = str.indexOf("}", index) + 1;
                int indexStart = str.indexOf("{", index);
                String p = str.substring(indexStart + 1, indexEnd - 1);
                SimpleDateFormat sdf = new SimpleDateFormat(p, Locale.CHINA);
                str.replace(index, indexEnd, sdf.format(new Date()));
            }
            return str.toString().trim();
        }
    }
}
